import asyncio
import json
import logging
import random
from fastapi import FastAPI, Request, HTTPException
import uvicorn
from tortoise.contrib.fastapi import register_tortoise
from config import config, EnvConfig
from handler import WXHandler, ChatHandler
from instructions.instruction import Instruction
from instructions.enum_types import ActionType
from models import init_db
from pydantic_models import WXMessageIn
from tools import basic_log_config

app = FastAPI()
uvicorn.config.LOGGING_CONFIG["formatters"]["default"]["fmt"] = "%(asctime)s - %(levelprefix)s %(message)s"
logger = logging.getLogger(__name__)

register_tortoise(
    app,
    config=config.TORTOISE_ORM,
    generate_schemas=True,
    add_exception_handlers=True,
)


async def compose_response(typeIn, content, isgroup, msg):
    """
    Controller函数，写在这里方便之后如果不用fastAPI,把处理逻辑和wx合并后方便转换的情况。
    "」\n- - - - - - -" in content
    :param typeIn:
    :param content:
    :param isgroup:
    :param msg:
    :return:
    """
    basic_log_config(config.LOG_DIR)
    wxHandler = WXHandler(typeIn, content, isgroup, msg)
    await wxHandler.chatDBHandler.init_requestor()
    instruction = await wxHandler.parse_intention()

    try:
        if not wxHandler.chatDBHandler.check_permission(instruction):
            logger.info("[chat] No permission to execute the instruction.")
            resType = "text"
            response = "你还不是用户，所以不配使唤我干这个~[旺柴]"
            return resType, response, "text"
        if isinstance(instruction, Instruction):
            logger.info(f"[chat] Parsed Query Intention: {instruction.insType}")
            responseRaw = await instruction.handle_query()
            await instruction.decorate_response(responseRaw)

            response = responseRaw.content
            resType = responseRaw.type.name.lower()
            desire_rtype = instruction.desire_rtype
        elif isinstance(instruction, str):
            logger.info(f"[chat] Maybe need help?")
            response = instruction
            resType = "text"
            desire_rtype = "text"
        else:
            responses = [
                "ENTJ - 卷王啊~",
                "INTJ - 阴暗逼是这样的",
                "ISFP - 温柔细腻小画家",
                "ENFP - 王道人格，快乐小狗是也",
                "INFJ - 小心绿老头黑化，世间的理想主义者",
                "ENFJ - 好为人师就是我，强者无需多言",
                "ISTJ - 看你看来我确实无趣，但挣得比你多",
                "ESTJ - 我的戒尺呢？",
                "ISTP - 骂人我是在行的。"
            ]
            response = random.choice(responses)
            resType = "text"
            desire_rtype = "text"
        wxHandler.chatDBHandler.answer = response
        wxHandler.chatDBHandler.add_actions(ActionType.QUERY_COMPLETED)
        await wxHandler.chatDBHandler.build_chat()
        return resType, response, desire_rtype
    except json.JSONDecodeError as e:
        wxHandler.chatDBHandler.add_actions(ActionType.JSON_ERROR)
        wxHandler.chatDBHandler.note = str(e)
        logger.error(f"Failed to decode JSON: {e}")
        raise HTTPException(status_code=400, detail="Invalid JSON")
    except Exception as e:
        wxHandler.chatDBHandler.add_actions(ActionType.HANDLER_QUERY_FAILED)
        wxHandler.chatDBHandler.note = str(e)
        logger.error(f"An error occurred: {e}")
        logger.exception(e)
        raise HTTPException(status_code=500, detail="Internal Server Error")


@app.get("/", tags=["TEST:Hello APP NAME"], summary="Hello nothing much, just for testing",
         description="Hello test",
         response_description="返回Hello APP NAME, to test it's running.")
async def hello():
    return f"Hello {config.APP_NAME}, Server is running."


@app.post("/chat", tags=["To handle the wechat information"],
          summary="Handle the wechat information, more info please refer to README.md")
async def chat(message: WXMessageIn):
    typeIn = message.type
    content = message.content
    isgroup = message.isgroup
    msg = message.msg
    logger.info(f"[chat]Receive Instruction: {content}, is in group: {isgroup}")
    resType, response, desire_rtype = await compose_response(typeIn, content, isgroup, msg)

    return {"msg": "OK", "type": resType, "desire_rtype": desire_rtype, "content": response}, 200

if __name__ == "__main__":
    # basic_log_config(config.LOG_DIR)
    asyncio.run(init_db())
    config = uvicorn.Config("app:app", port=config.SERVER_PORT, host=config.SERVER_HOST,
                            reload=True)
    server = uvicorn.Server(config)
    logger.info("Starting server")
    server.run()
